#define MaxLights 2


float4x4	World;
float4x4	View;
float4x4	Projection;

int			activePointLights;
float3      LightPointPosition[MaxLights];
float4		LightPointColor[MaxLights];

int			activeSpotLights;
float3		lightSpotDirection[MaxLights];
float		lightSpotDecayExponent[MaxLights];
float		lightSpotAngleCosine[MaxLights];

float3      LightSpotPosition[MaxLights];
float4		LightSpotColor[MaxLights];

float4		SpecularColor;
float		SpecularPower;
float		SpecularIntensity;
float4      AmbientColor;
float		AmbientIntensity;
float		DiffuseIntensity;


float3      camPosition;
float		clipSide;
float		clipPlaneY;



bool	fogEnabled;
float	fogBegins;
float	fogEnds;

Texture2D	textureFromFile;
Texture2D	billboard;
Texture2D	TVTexture;
TextureCube textureCube;

sampler DiffuseSampler : register(s00) =
sampler_state
{
	Magfilter = ANISOTROPIC;
	Mipfilter = Linear;

};

sampler DiffuseTextureSampler =
sampler_state
{
	texture = <textureFromFile>;
	Magfilter = Point;
	Mipfilter = NONE;

};


sampler BillboardSampler =
sampler_state
{
	texture = <billboard>;
};




sampler cubeSampler = sampler_state {
	texture = <textureCube>;
	MipFilter = POINT;
	MinFilter = POINT;
	MagFilter = POINT;
	AddressU = CLAMP;
	AddressV = CLAMP;
};


struct VertexShaderInput
{
	float3 Position : POSITION0;
	float3 Normal : Normal0;
	float2 TexCoord : TexCoord0;
};


struct VertexShaderOutput
{
	float4 Position			: POSITION0;
	float3 N				: TEXCOORD0;
	float2 TextureCoord		: TEXCOORD1;
	float3 V				: TEXCOORD2;
	float3 WorldPosition	: TEXCOORD3;
	float4 clipping :  TEXCOORD4;

};


VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;

	float4 worldPosition = mul(float4(input.Position, 1), World);
		float4 viewPosition = mul(worldPosition, View);
		output.Position = mul(viewPosition, Projection);

	output.N = mul(float4(input.Normal, 0), World);
	output.TextureCoord = input.TexCoord;
	output.V = camPosition - worldPosition;
	output.WorldPosition = worldPosition;
	output.clipping = float4(0, 0, 0, 0);
	float4 wg = float4(2, 2, 2, 2);
		output.clipping.x = (input.Position.y + clipPlaneY) *clipSide;
	return output;
}

float4 PixelShaderAmbientFunction(VertexShaderOutput input) : COLOR0
{
	clip(input.clipping.x);
	float4 finalColor = float4(0, 0, 0, 0);
		float4 diffuseColor = float4(1, 1, 1, 1);
		float3 Normal = normalize(input.N);
		float3 ViewDir = normalize(input.V);

		for (int i = 0; i < activePointLights; i++)
		{
		float3 LightDir = normalize(LightPointPosition[i] - input.WorldPosition);
			float Diff = saturate(dot(Normal, LightDir));
		float Specular = 0;
		if (Diff > 0)
		{
			float3 Reflect = normalize(2 * Diff * Normal - LightDir);
				Specular = pow(saturate(dot(Reflect, ViewDir)), SpecularPower);
		}
		finalColor += AmbientColor*AmbientIntensity + LightPointColor[i] * DiffuseIntensity * diffuseColor * Diff + SpecularIntensity * SpecularColor * Specular;
		}

	for (int j = 0; j < activeSpotLights; j++)
	{
		float3 LightDir = LightSpotPosition[j] - input.WorldPosition;
			LightDir = normalize(LightDir);
		float SdL = dot(lightSpotDirection[j], -LightDir);

		if (SdL > lightSpotAngleCosine[j])
		{
			float spotIntensity = pow(abs(SdL), lightSpotDecayExponent[j]);
			float3 Normal = normalize(input.N);
				float3 ViewDir = normalize(input.V);
				float Diff = saturate(dot(Normal, LightDir));
			float Specular = 0;
			if (Diff >0)
			{
				float3 Reflect = normalize(2 * Diff * Normal - LightDir);
					Specular = pow(saturate(dot(Reflect, ViewDir)), SpecularPower);
			}
			finalColor += AmbientColor*AmbientIntensity + spotIntensity * LightSpotColor[j] * DiffuseIntensity * diffuseColor * Diff + SpecularIntensity * SpecularColor * Specular;
		}
	}
	finalColor.a = 1;
	if (fogEnabled)
		finalColor = lerp(finalColor, float4(0.75, 0.75, 0.75f, 1.0f), saturate((length(input.V) - fogBegins) / (fogEnds - fogBegins)));
	return finalColor;
}



float4 PixelShaderAmbientTexturedFunction(VertexShaderOutput input) : COLOR0
{
	clip(input.clipping.x);
	float4 finalColor = float4(0, 0, 0, 0);
		float4 diffuseColor = tex2D(DiffuseTextureSampler, input.TextureCoord);
		float3 Normal = normalize(input.N);
		float3 ViewDir = normalize(input.V);

		for (int i = 0; i < activePointLights; i++)
		{
		float3 LightDir = normalize(LightPointPosition[i] - input.WorldPosition);
			float Diff = saturate(dot(Normal, LightDir));
		float Specular = 0;
		if (Diff > 0)
		{
			float3 Reflect = normalize(2 * Diff * Normal - LightDir);
				Specular = pow(saturate(dot(Reflect, ViewDir)), SpecularPower);
		}
		finalColor += AmbientColor*AmbientIntensity + LightPointColor[i] * DiffuseIntensity * diffuseColor * Diff + SpecularIntensity * SpecularColor * Specular;

		}

	for (int j = 0; j < activeSpotLights; j++)
	{
		float3 LightDir = LightSpotPosition[j] - input.WorldPosition;
			LightDir = normalize(LightDir);
		float SdL = dot(lightSpotDirection[j], -LightDir);

		if (SdL > lightSpotAngleCosine[j])
		{
			float spotIntensity = pow(abs(SdL), lightSpotDecayExponent[j]);
			float3 Normal = normalize(input.N);
				float3 ViewDir = normalize(input.V);
				float Diff = saturate(dot(Normal, LightDir));
			float Specular = 0;
			if (Diff >0)
			{
				float3 Reflect = normalize(2 * Diff * Normal - LightDir);
					Specular = pow(saturate(dot(Reflect, ViewDir)), SpecularPower);
			}
			finalColor += AmbientColor*AmbientIntensity + spotIntensity * LightSpotColor[j] * DiffuseIntensity * 4 * diffuseColor * Diff + SpecularIntensity * SpecularColor * Specular;
		}
	}
	finalColor.a = 1;
	if (fogEnabled)
		finalColor = lerp(finalColor, float4(0.75, 0.75, 0.75f, 1.0f), saturate((length(input.V) - fogBegins) / (fogEnds - fogBegins)));
	return finalColor;
}


float4 PixelShaderBillboardFunction(VertexShaderOutput input) : COLOR0
{
	clip(input.clipping.x);
	float4 finalColor = float4(0, 0, 0, 0);
		float4 diffuseColor = tex2D(BillboardSampler, input.TextureCoord);
		float4 alphaColor = tex2D(BillboardSampler, float2(0, 0));
		finalColor = diffuseColor;
	if (fogEnabled)
		finalColor = lerp(finalColor, float4(0.75, 0.75, 0.75f, 1.0f), saturate((length(input.V) - fogBegins) / (fogEnds - fogBegins)));
	if (diffuseColor.x == alphaColor.x && diffuseColor.y == alphaColor.y && diffuseColor.z == alphaColor.z)
	{
		finalColor.a = 0;
	}

	return finalColor;
}


float4 TVPixelShaderAmbientFunction(VertexShaderOutput input) : COLOR0
{
	clip(input.clipping.x);
	float4 finalColor = float4(0, 0, 0, 0);
		float4 diffuseColor = TVTexture.Sample(DiffuseSampler, input.TextureCoord);

		finalColor = diffuseColor;
	if (fogEnabled)
		finalColor = lerp(finalColor, float4(0.75, 0.75, 0.75f, 1.0f), saturate((length(input.V) - fogBegins) / (fogEnds - fogBegins)));
	return finalColor;
}

float4 SpherePixelShaderAmbientFunction(VertexShaderOutput input) : COLOR0
{
	clip(input.clipping.x);
	float3 N = normalize(input.N);
		float3 I = -input.V;
		I = normalize(I);

	float3 R = reflect(I, N);
		R = normalize(R);
	float3 reflectedColor = texCUBE(cubeSampler, R);
		float4 finalColor = float4(reflectedColor, 1);
		if (fogEnabled)
			finalColor = lerp(finalColor, float4(0.75, 0.75, 0.75f, 1.0f), saturate((length(input.V) - fogBegins) / (fogEnds - fogBegins)));
	return finalColor;
}

technique TechniqueNormal
{

	pass Pass1
	{
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 PixelShaderAmbientFunction();
	}

}

technique TechniqueNormalTextured
{

	pass Pass1
	{
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 PixelShaderAmbientTexturedFunction();
	}

}

technique TechniqueBillboard
{

	pass Pass1
	{
		AlphaBlendEnable = TRUE;
		DestBlend = INVSRCALPHA;
		SrcBlend = SRCALPHA;
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 PixelShaderBillboardFunction();
	}

}

technique TechniqueTV
{

	pass Pass1
	{
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 TVPixelShaderAmbientFunction();
	}

}

technique TechniqueSphere
{

	pass Pass1
	{
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 SpherePixelShaderAmbientFunction();
	}

}